"""
数据库备份核心模块

提供数据库备份的基础功能，包括连接管理、配置处理等。
"""

import os
import logging
import tomllib
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any
from datetime import datetime
from .config.templates import ConfigTemplates


class DatabaseBackup(ABC):
    """数据库备份基类
    
    所有数据库备份类的基类，定义统一的接口规范。
    """
    
    def __init__(self, host: str, port: int, username: str, password: str, 
                 database: str, backup_dir: str = "backups"):
        """初始化数据库备份实例
        
        参数:
            host (str): 数据库主机地址
                示例值: "localhost"
            port (int): 数据库端口
                示例值: 3306
            username (str): 数据库用户名
                示例值: "root"
            password (str): 数据库密码
                示例值: "password123"
            database (str): 数据库名称
                示例值: "my_database"
            backup_dir (str): 备份文件存储目录
                示例值: "backups"
        
        返回:
            DatabaseBackup: 数据库备份实例
        """
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.database = database
        self.backup_dir = backup_dir
        self.logger = self._setup_logging()
        
        # 确保备份目录存在
        os.makedirs(self.backup_dir, exist_ok=True)
    
    def _setup_logging(self) -> logging.Logger:
        """设置日志记录器
        
        返回:
            logging.Logger: 配置好的日志记录器
                示例值: <Logger database_backup.core (INFO)>
        """
        logger = logging.getLogger(f"database_backup.{self.__class__.__name__}")
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
        return logger
    
    @abstractmethod
    def connect(self) -> bool:
        """连接到数据库
        
        返回:
            bool: 连接是否成功
                示例值: True
        """
        pass
    
    @abstractmethod
    def disconnect(self) -> bool:
        """断开数据库连接
        
        返回:
            bool: 断开是否成功
                示例值: True
        """
        pass
    
    @abstractmethod
    def get_tables(self) -> List[str]:
        """获取数据库中的所有表名
        
        返回:
            List[str]: 表名列表
                示例值: ["users", "products", "orders"]
        """
        pass
    
    @abstractmethod
    def backup_table(self, table_name: str, output_file: str) -> bool:
        """备份单个数据表
        
        参数:
            table_name (str): 表名
                示例值: "users"
            output_file (str): 输出文件路径
                示例值: "backups/users_20231201.sql"
        
        返回:
            bool: 备份是否成功
                示例值: True
        """
        pass
    
    def backup_all_tables(self, include_data: bool = True) -> Dict[str, Any]:
        """备份所有数据表
        
        参数:
            include_data (bool): 是否包含数据（True包含数据，False只备份结构）
                示例值: True
        
        返回:
            Dict[str, Any]: 备份结果信息
                示例值: {
                    "success": True,
                    "backup_files": ["backups/users_20231201.sql", "backups/products_20231201.sql"],
                    "tables_backed_up": 5,
                    "total_size": "2.5MB",
                    "backup_time": "2023-12-01 10:30:00"
                }
        """
        self.logger.info(f"开始备份数据库 {self.database} 的所有表")
        
        try:
            if not self.connect():
                return {
                    "success": False,
                    "error": "数据库连接失败",
                    "backup_files": [],
                    "tables_backed_up": 0,
                    "total_size": "0B",
                    "backup_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                }
            
            tables = self.get_tables()
            backup_files = []
            successful_tables = 0
            
            for table in tables:
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                backup_file = os.path.join(
                    self.backup_dir, 
                    f"{table}_{timestamp}.sql"
                )
                
                if self.backup_table(table, backup_file):
                    backup_files.append(backup_file)
                    successful_tables += 1
                    self.logger.info(f"成功备份表 {table} 到 {backup_file}")
                else:
                    self.logger.error(f"备份表 {table} 失败")
            
            # 计算总文件大小
            total_size = sum(os.path.getsize(f) for f in backup_files)
            total_size_str = self._format_file_size(total_size)
            
            result = {
                "success": successful_tables == len(tables),
                "backup_files": backup_files,
                "tables_backed_up": successful_tables,
                "total_tables": len(tables),
                "total_size": total_size_str,
                "backup_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
            
            self.disconnect()
            self.logger.info(f"数据库备份完成: {successful_tables}/{len(tables)} 个表备份成功")
            return result
            
        except Exception as e:
            self.logger.error(f"备份过程中发生错误: {str(e)}")
            return {
                "success": False,
                "error": str(e),
                "backup_files": [],
                "tables_backed_up": 0,
                "total_size": "0B",
                "backup_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
    
    def _format_file_size(self, size_bytes: int) -> str:
        """格式化文件大小
        
        参数:
            size_bytes (int): 文件大小（字节）
                示例值: 1024
        
        返回:
            str: 格式化后的文件大小
                示例值: "1.0KB"
        """
        if size_bytes < 1024:
            return f"{size_bytes}B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f}KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes / (1024 * 1024):.1f}MB"
        else:
            return f"{size_bytes / (1024 * 1024 * 1024):.1f}GB"


class DatabaseBackupConfig:
    """数据库备份配置类
    
    管理数据库备份的配置信息，包括数据库连接、备份设置等。
    """
    
    def __init__(self, config_file: str = None, **kwargs):
        """初始化配置实例
        
        参数:
            config_file (str, optional): 配置文件路径
                示例值: "config.toml"
            **kwargs: 其他配置参数
                示例值: host="localhost", port=3306
        """
        self.config_file = config_file or "config.toml"
        
        if kwargs:
            # 如果提供了关键字参数，则使用这些参数初始化
            self._init_from_kwargs(kwargs)
        else:
            # 否则从配置文件加载
            self.config = self._load_config()
    
    def _init_from_kwargs(self, kwargs: Dict[str, Any]):
        """从关键字参数初始化配置
        
        参数:
            kwargs (Dict[str, Any]): 配置参数
        """
        # 设置基本属性
        self.host = kwargs.get('host', 'localhost')
        self.port = kwargs.get('port', 3306)
        self.user = kwargs.get('user', '')
        self.username = kwargs.get('username', '') or self.user  # 兼容user和username
        self.password = kwargs.get('password', '')
        self.database = kwargs.get('database', '')
        self.output_dir = kwargs.get('output_dir', './backups')
        self.filename = kwargs.get('filename', '')
        self.tables = kwargs.get('tables', [])
        self.exclude_tables = kwargs.get('exclude_tables', [])
        self.compress = kwargs.get('compress', False)
        self.include_data = kwargs.get('include_data', True)
        self.include_schema = kwargs.get('include_schema', True)
        self.ssl_mode = kwargs.get('ssl_mode', None)
        
        # 设置配置字典（用于兼容旧代码）
        self.config = {
            "type": "mysql",
            "backup": {
                "backup_dir": self.output_dir,
                "auto_upload": False
            },
            "database": {
                "host": self.host,
                "port": self.port,
                "username": self.username,
                "password": self.password,
                "database": self.database
            }
        }
    
    def _load_config(self) -> Dict[str, Any]:
        """加载配置文件
        
        返回:
            Dict[str, Any]: 配置信息
                示例值: {
                    "mysql": {
                        "host": "localhost",
                        "port": 3306,
                        "username": "root",
                        "password": "password123",
                        "database": "my_db"
                    },
                    "backup_dir": "backups"
                }
        """
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'rb') as f:  # tomllib需要二进制模式
                    return tomllib.load(f)
            except Exception as e:
                logging.error(f"加载配置文件失败: {e}")
        
        # 返回默认配置
        return {
            "type": "mysql",
            "backup": {
                "backup_dir": "backups",
                "git_repository": None,
                "auto_upload": False
            },
            "database": {
                "host": "localhost",
                "port": 3306,
                "username": "root",
                "password": "password123",
                "database": "my_database"
            }
        }
    
    def save_config(self, config: Dict[str, Any]) -> bool:
        """保存配置到文件
        
        参数:
            config (Dict[str, Any]): 配置信息
                示例值: {
                    "mysql": {"host": "localhost", "port": 3306},
                    "backup_dir": "backups"
                }
        
        返回:
            bool: 保存是否成功
                示例值: True
        """
        try:
            # 确保目录存在
            os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
            
            # 使用tomllib写入配置文件
            # 注意：Python 3.11+的tomllib只提供读取功能，不提供写入功能
            # 我们需要手动实现TOML格式的写入
            with open(self.config_file, 'w', encoding='utf-8') as f:
                f.write("# Database Backup Configuration\n")
                f.write("# Generated by database-backup tool\n\n")
                
                # 写入数据库配置
                if 'database' in config:
                    f.write("[database]\n")
                    for key, value in config['database'].items():
                        if isinstance(value, str):
                            f.write(f'{key} = "{value}"\n')
                        else:
                            f.write(f'{key} = {value}\n')
                    f.write("\n")
                
                # 写入备份配置
                if 'backup' in config:
                    f.write("[backup]\n")
                    for key, value in config['backup'].items():
                        if isinstance(value, str):
                            f.write(f'{key} = "{value}"\n')
                        elif isinstance(value, bool):
                            f.write(f'{key} = {str(value).lower()}\n')
                        else:
                            f.write(f'{key} = {value}\n')
                    f.write("\n")
                
                # 写入类型配置
                if 'type' in config:
                    f.write(f'type = "{config["type"]}"\n')
            
            return True
        except Exception as e:
            logging.error(f"保存配置文件失败: {e}")
            return False
    
    def get_database_config(self) -> Optional[Dict[str, Any]]:
        """获取数据库配置
        
        返回:
            Optional[Dict[str, Any]]: 数据库配置信息
                示例值: {
                    "host": "localhost",
                    "port": 3306,
                    "username": "root",
                    "password": "password123",
                    "database": "my_db"
                }
        """
        return self.config.get("database")
    
    def update_database_config(self, config: Dict[str, Any]) -> bool:
        """更新数据库配置
        
        参数:
            config (Dict[str, Any]): 新的配置信息
                示例值: {"host": "192.168.1.100", "port": 3307}
        
        返回:
            bool: 更新是否成功
                示例值: True
        """
        self.config["database"] = config
        return self.save_config(self.config)
    
    def get_database_type(self) -> str:
        """获取数据库类型
        
        返回:
            str: 数据库类型
                示例值: "mysql"
        """
        return self.config.get("type", "mysql")
    
    @staticmethod
    def generate_template_config() -> Dict[str, Any]:
        """生成TOML配置模板
        
        返回:
            Dict[str, Any]: 配置模板
                示例值: {
                    "type": "mysql",
                    "backup": {
                        "backup_dir": "backups",
                        "auto_upload": false,
                        "git_repository": null
                    },
                    "database": {
                        "host": "localhost",
                        "port": 3306,
                        "username": "root",
                        "password": "password123",
                        "database": "my_database"
                    }
                }
        """
        return ConfigTemplates.get_backup_config_dict()